<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!-- 以前js都是放在沙箱中,自己实现的沙箱 跑的 ->
     如果代码放在iframe 中跑呢
     我们的css隔离-(scopedCSS)->web组件化的css隔离
     渲染采用-webcomponents->[拉去]
     --->
    <div>基座的代码-不被子应用的样式所污染</div>


    <div id="container"></div>

    <script>


        const jsTemplate = `
            window.a = '子应用的js';
            const innerDiv = document.querySelector('#inner');
            console.log(innerDiv, 'innerDiv');
        `;

        // 修正后的strTemplate - 确保HTML结构完整
        const strTemplate = `
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>子应用</title>
            </head>
            <body>
                <div>子应用的代码</div>
                <div id="inner"></div>
            </body>
            </html>
        `;


        // 创建iframe
        function createIframe() {

            const iframe = document.createElement('iframe');
            iframe.src = 'about:blank';
            document.body.appendChild(iframe);
            return iframe;
        }
        //创建沙箱
        function ceateSandbox() {
            const sandbox = {
                iframe: createIframe(), // 创建一个iframe 沙箱
                shadowRoot: null
            }
            return sandbox;
        }


        function injectTemplate(sandbox, template) {
            const wrapper = document.createElement('div');
            wrapper.innerHTML = template;
            sandbox.shadowRoot.appendChild(wrapper);
        }

        function runScriptInSandbox(sandbox, js) {
            const iframeWindow = sandbox.iframe.contentWindow;
            const script = iframeWindow.document.createElement('script');
            // 我们希望在脚本执行之前， 有些方法使用父应用的
            // document.querySelector('')应该用的不是iframe 中的 -->去shadowRoot 中去找
            // 添加弹窗的时候 document.createElement('div').appendChild()--->应该代理到主应用的window 对象上
            // iframe 中的路由系统（因为iframe 中有自己独特的路由系统）例如 history.pushState-->应该代理到主应用的路由系统上

            Object.defineProperty(iframeWindow.Document.prototype, 'querySelector', {
                get() {
                    return new Proxy(sandbox.shadowRoot['querySelector'], {
                        apply(target, thisArg, args) {
                            return thisArg.querySelector.apply(sandbox.shadowRoot, args);
                        }
                    });
                }
            });

            script.textContent = js;
            iframeWindow.document.body.appendChild(script);
        }
        // 定义一个组件
        function createComponent(template, js) {
            class WujieApp extends HTMLElement {
                // 挂载
                connectedCallback() {
                    // 创建沙箱
                    const sandbox = ceateSandbox();
                    // 创建shdowDom
                    sandbox.shadowRoot = this.attachShadow({ mode: 'open' });
                    // 将html css 放入到shadowDom中
                    injectTemplate(sandbox, strTemplate);
                    // 将js放入到沙箱中
                    runScriptInSandbox(sandbox, jsTemplate);

                }
            }

            window.customElements.define('wujie-app', WujieApp);
            container.appendChild(document.createElement('wujie-app'));

        }

        createComponent()

    </script>

</body>

</html>